package com.cnbm.wcsbasic.protocol.netty.modbus.moban;

import com.cnbm.wcsbasic.protocol.netty.io.common.Package;
import com.cnbm.wcsbasic.protocol.netty.io.common.RcvPackage;
import com.cnbm.wcsbasic.protocol.netty.io.common.byteutils.ByteUtils;
import com.cnbm.wcsbasic.protocol.netty.io.common.enmuc.ModbusFC;
import com.cnbm.wcsbasic.protocol.netty.io.common.enmuc.PlcVarType;
import com.cnbm.wcsbasic.protocol.netty.io.param.PlcVar;
import com.cnbm.wcsbasic.protocol.netty.modbus.entity.ReadRequestFrame;
import com.cnbm.wcsbasic.protocol.netty.modbus.entity.WriteRequestFrame;

import java.util.ArrayList;
import java.util.List;

/**
 * @Desc: ""
 * @Author: caixiang
 * @DATE: 2024-06-07 13:29
 */
public class ModbusPlcVar implements PlcVar {


    //常量区域     开始
    private String name;
    private ModbusFC fc;
    private PlcVarType type;
    //MB_HOLD_REG 区块的 地址是从 00 开始的
    private Integer address;
    //length = 1代表 非数组;;;       length > 1 代表数组  ;; 注意 length这个参数 是实际plc中 数组的长度，和read操作相关
    //如果是String 类型不用填length 只需要填string类型的起始位置就行了，我会自己去取数据长度（也就是说这里的length并不是string 的长度）。
    private Integer length;
    //这个字段只是给 字符串变量 和 字符串数组 用, 这个字段是plc中设置的最大String长度
    private Integer strSize;
    private Integer unitId;
    //常量区域     结束


    @Override
    public String protocolName() {
        return "Modbus Tcp";
    }

    public ModbusPlcVar(String name, Integer unitId, ModbusFC fc, PlcVarType type, Integer address, Integer length, Integer strSize) {
        this.name = name;
        this.unitId = unitId;
        this.fc = fc;
        this.type = type;
        this.address = address;
        this.length = length;
        this.strSize = strSize;

    }



    @Override
    public Package toBytes() {
        ReadRequestFrame readRequestFrame = new ReadRequestFrame(
                this.unitId,
                this.fc,
                this.address,
                this.length,
                this.strSize,
                this.type
        );
        return new Package(readRequestFrame.toBytes(),readRequestFrame.getTransationId());
    }

    @Override
    public Package toBytes(Object newValue) {
        WriteRequestFrame writeRequestFrame = new WriteRequestFrame(this.unitId,
                this.fc,
                this.type,
                this.address,
                newValue
        );
        return new Package(writeRequestFrame.toBytes(),writeRequestFrame.getTransationId());
    }
    public RcvPackage isValidOfFunctioncode(Byte code){

        boolean isOK = false;
        String content = "";
        if(ByteUtils.getByteSignbit(code, false)){
            //负数
            isOK = false;
            if(code.equals(Byte.valueOf("-127"))){

                content = "非法功能";

            }else if(code.equals(Byte.valueOf("-126"))){

                content = "非法数据地址";

            }else if(code.equals(Byte.valueOf("-125"))){

                content = "非法数据值";

            }else if(code.equals(Byte.valueOf("-124"))){

                content = "从站设备故障";

            }else if(code.equals(Byte.valueOf("-123"))){

                content = "确认";

            }else if(code.equals(Byte.valueOf("-122"))){

                content = "服务器繁忙";

            }else if(code.equals(Byte.valueOf("-121"))){

                content = "存储奇偶性差错";

            }else if(code.equals(Byte.valueOf("-118"))){

                content = "不可用网关路径";

            }else if(code.equals(Byte.valueOf("-117"))){

                content = "网关目标设备响应失败";

            }else {

                content = "其他错误";

            }
        }else {

            isOK = true;
            content = "没错误";
        }
        return new RcvPackage(isOK,null,content);
    }

    @Override
    public RcvPackage toObjectForRead(Package response) {

        byte[] allBytes = response.getBody();


        RcvPackage responseRes = isValidOfFunctioncode(allBytes[7]);
        //这里做检验 判断
        byte[] content = null;
        if(responseRes.isOk()){
            //数据长度
            Integer contentInt = ByteUtils.toInt(allBytes[8]);
            content = new byte[contentInt];
            System.arraycopy(allBytes, 9, content, 0, contentInt);

            Object object = this.type.toObject(content);
            responseRes.setValue(handleRes(this.type, this.length, object));
            return responseRes;
        }else {
            return responseRes;
        }
    }

    @Override
    public RcvPackage toObjectForWrite(Package response) {
        byte[] allBytes = response.getBody();
        return isValidOfFunctioncode(allBytes[7]);
    }

    @Override
    public String toString() {
        return "ModbusPlcVar{" +
                "name='" + name + '\'' +
                ", type=" + type +
                ", fc=" + fc +
                ", address=" + address +
                ", length=" + length +
                ", strSize=" + strSize +
                ", unitId=" + unitId +
                '}';
    }

    //处理结果
    private Object handleRes(PlcVarType plcVarType, Integer length, Object object){
        if(plcVarType.isArray() && plcVarType.getName().equals("BOOL")){
            List<Boolean> list = (List<Boolean>) object;
            List<Boolean> listRes = new ArrayList<Boolean>();
            for(int i=0;i<length;i++){
                listRes.add(list.get(i));
            }
            return listRes;
        } else if(plcVarType.isArray() && plcVarType.getName().equals("BYTE")){
            List<Byte> list = (List<Byte>) object;
            List<Byte> listRes = new ArrayList<Byte>();
            for(int i=0;i<length;i++){
                listRes.add(list.get(i));
            }
            return listRes;
        }
        return object;
    }



}
